﻿using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Centido.Core.Dto;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Centido.Core.Test
{
    /// <summary>
    ///   Testing the data transfer object for a security role.
    /// </summary>
    [TestClass]
    public class RoleDtoTest : GenericDtoTest
    {
        /// <summary>
        ///   The current domain name.
        /// </summary>
        public const string DomainName = "FullAdminRights";

        /// <summary>
        ///   The current domain.
        /// </summary>
        private Domain _domain;


        /// <summary>
        /// Test initialiaze
        /// </summary>
        [TestInitialize]
        public void Initialize()
        {
            _domain = Domain.Build(DomainConfiguration.Load(DomainName));

            _domain.DeleteAll();
        }


        /// <summary>
        /// Test clean up
        /// </summary>
        [TestCleanup]
        public void CleanUp()
        {
            _domain.DeleteAll();
        }


        /// <summary>
        ///   Retrieves the name of the data transfer object xml tag.
        /// </summary>
        /// <returns></returns>
        protected override string GetXmlTag()
        {
            return RoleDto.XmlTag;
        }


        /// <summary>
        ///   Retrives the current xml schema version.
        /// </summary>
        /// <returns></returns>
        protected override string GetCurrentXmlSchemaVersion()
        {
            return RoleDto.CurrentXmlSchemaVersion;
        }


        /// <summary>
        ///   Creates a new data transfer object.
        /// </summary>
        /// <returns></returns>
        protected override DataTransferObject CreateDto()
        {
            return new RoleDto
            {
                Name = "my_role",
                DisplayName = "The role display name"
            };
        }


        /// <summary>
        ///   Retrieves the list of data transfer object fields.
        /// </summary>
        /// <returns></returns>
        protected override IEnumerable<DtoFieldInfo> GetFields()
        {
            yield return new DtoFieldInfo
            {
                Name = "Name",
                XmlName = RoleDto.NameAttribute,
                IsRequired = true,
                FieldType = DtoFieldType.String,
                SampleValue = "role_name",
                IsCopiedFromDto = false
            };

            yield return new DtoFieldInfo
            {
                Name = "DisplayName",
                XmlName = RoleDto.DisplayNameAttribute,
                IsRequired = false,
                FieldType = DtoFieldType.String,
                SampleValue = "Display name"
            };
        }


        /// <summary>
        ///   Copies the properties of the data transfer object to the corresponding object.
        /// </summary>
        /// <param name="dto">The data transfer object.</param>
        /// <returns>Returns the corresponding object after copying.</returns>
        protected override object CopyFrom(DataTransferObject dto)
        {
            var role = _domain.AddRole(StringProperty.RandomIdentifier());
            
            ((RoleDto)dto).CopyTo(role);

            return role;
        }


        /// <summary>
        ///   Creates a data transfer object from the correpsonding object.
        /// </summary>
        /// <param name="dto">The created data transfer object.</param>
        /// <param name="initialObject">The initial object.</param>
        protected override void CreateDtoFromObject(out DataTransferObject dto, out object initialObject)
        {
            var role = _domain.AddRole(StringProperty.RandomIdentifier());

            dto = RoleDto.CreateFrom(role);
            initialObject = role;
        }


        /// <summary>
        ///   Reading user list from xml.
        /// </summary>
        [TestMethod]
        public void ReadingUserListFromXml()
        {
            // Creating the role
            var xml = string.Format("<{0} {1}=\"{2}\">",
                RoleDto.XmlTag,
                RoleDto.NameAttribute,
                StringProperty.RandomIdentifier());

            // Creating the user list
            xml += string.Format("<{0}><{1} {2}=\"{3}\" /><{4} {5}=\"{6}\"></{7}></{8}></{9}>",
                RoleDto.UserListTag,
                RoleDto.UserTag,
                RoleDto.UserNameAttribute,
                StringProperty.RandomIdentifier(),
                RoleDto.UserTag,
                RoleDto.UserNameAttribute,
                StringProperty.RandomIdentifier(),
                RoleDto.UserTag,
                RoleDto.UserListTag,
                RoleDto.XmlTag);

            var stream = new XmlTextReader(new MemoryStream(Encoding.UTF8.GetBytes(xml)));

            var roleDto = new RoleDto();

            roleDto.ReadXml(stream);

            Assert.AreEqual(roleDto.UserNames.Count(), 2);
        }


        /// <summary>
        ///   Reading an empty users list from xml.
        /// </summary>
        [TestMethod]
        public void ReadingEmptyUserListFromXml()
        {
            var xml = string.Format("<{0} {1}=\"{2}\">",
               RoleDto.XmlTag,
               RoleDto.NameAttribute,
               StringProperty.RandomIdentifier());

            // Creating the empty user list
            xml += string.Format("<{0} /></{1}>",
                RoleDto.UserListTag,
                RoleDto.XmlTag);

            var stream = new XmlTextReader(new MemoryStream(Encoding.UTF8.GetBytes(xml)));

            var roleDto = new RoleDto();

            roleDto.ReadXml(stream);

            Assert.AreEqual(roleDto.UserNames.Count(), 0);
        }


        /// <summary>
        ///   Writing and reading the user list.
        /// </summary>
        [TestMethod]
        public void WritingAndReadingUserList()
        {
            var roleDto = new RoleDto
            {
                Name = StringProperty.RandomIdentifier()
            };

            roleDto.AddUser("user_a");
            roleDto.AddUser("user_b");

            var memoryStream = new MemoryStream();
            var writer = new XmlTextWriter(memoryStream, Encoding.UTF8);

            roleDto.WriteXml(writer);

            writer.Flush();

            memoryStream.Position = 0;
            var streamReader = new StreamReader(memoryStream);
            var xml = streamReader.ReadToEnd();

            Assert.IsFalse(string.IsNullOrEmpty(xml));

            memoryStream.Position = 0;
            var reader = new XmlTextReader(memoryStream);

            var dto = new RoleDto();

            dto.ReadXml(reader);

            Assert.AreEqual(dto.UserNames.Count(), 2);
            Assert.AreEqual(dto.UserNames.Count(n => n == "user_a"), 1);
            Assert.AreEqual(dto.UserNames.Count(n => n == "user_b"), 1);
        }


        /// <summary>
        ///   Reading the child role list from xml.
        /// </summary>
        [TestMethod]
        public void ReadingChildRoleListFromXml()
        {
            // Creating the role
            var xml = string.Format("<{0} {1}=\"{2}\">",
                RoleDto.XmlTag,
                RoleDto.NameAttribute,
                StringProperty.RandomIdentifier());

            // Creating the child role list
            xml += string.Format("<{0}><{1} {2}=\"{3}\" /><{4} {5}=\"{6}\"></{7}></{8}></{9}>",
                RoleDto.ChildRoleListTag,
                RoleDto.ChildRoleTag,
                RoleDto.ChildRoleNameAttribute,
                StringProperty.RandomIdentifier(),
                RoleDto.ChildRoleTag,
                RoleDto.ChildRoleNameAttribute,
                StringProperty.RandomIdentifier(),
                RoleDto.ChildRoleTag,
                RoleDto.ChildRoleListTag,
                RoleDto.XmlTag);

            var stream = new XmlTextReader(new MemoryStream(Encoding.UTF8.GetBytes(xml)));

            var roleDto = new RoleDto();

            roleDto.ReadXml(stream);

            Assert.AreEqual(roleDto.ChildRoleNames.Count(), 2);
        }


        /// <summary>
        ///   Reading an empty child role list from xml.
        /// </summary>
        [TestMethod]
        public void ReadingEmptyChildRoleListFromXml()
        {
            var xml = string.Format("<{0} {1}=\"{2}\">",
               RoleDto.XmlTag,
               RoleDto.NameAttribute,
               StringProperty.RandomIdentifier());

            // Creating the empty child role list
            xml += string.Format("<{0} /></{1}>",
                RoleDto.ChildRoleListTag,
                RoleDto.XmlTag);

            var stream = new XmlTextReader(new MemoryStream(Encoding.UTF8.GetBytes(xml)));

            var roleDto = new RoleDto();

            roleDto.ReadXml(stream);

            Assert.AreEqual(roleDto.ChildRoleNames.Count(), 0);
        }


        /// <summary>
        ///   Writing and reading the child role list.
        /// </summary>
        [TestMethod]
        public void WritingAndReadingChildRoleList()
        {
            var roleDto = new RoleDto
            {
                Name = StringProperty.RandomIdentifier()
            };

            roleDto.AddChildRole("role_a");
            roleDto.AddChildRole("role_b");

            var memoryStream = new MemoryStream();
            var writer = new XmlTextWriter(memoryStream, Encoding.UTF8);

            roleDto.WriteXml(writer);

            writer.Flush();

            memoryStream.Position = 0;
            var streamReader = new StreamReader(memoryStream);
            var xml = streamReader.ReadToEnd();

            Assert.IsFalse(string.IsNullOrEmpty(xml));

            memoryStream.Position = 0;
            var reader = new XmlTextReader(memoryStream);

            var dto = new RoleDto();

            dto.ReadXml(reader);

            Assert.AreEqual(dto.ChildRoleNames.Count(), 2);
            Assert.AreEqual(dto.ChildRoleNames.Count(n => n == "role_a"), 1);
            Assert.AreEqual(dto.ChildRoleNames.Count(n => n == "role_b"), 1);
        }
    }
}
